import random
import re

from datetime import date, datetime
from flask import request, abort, make_response, jsonify, current_app, session

from info import redis_store, constants, db
from info.constants import IMAGE_CODE_REDIS_EXPIRES
from info.models import User
from info.utils.captcha.captcha import captcha
from info.utils.response_code import RET
from info.utils.yuntongxun.sms import CCP
from . import passport_blu


@passport_blu.route('/logout', methods=['post', 'get'])
def logout():
    """
    退出功能实现
    :return:
    """
    # 1.清空session
    session.pop('user_id')
    session.pop('user_mobile')
    session.pop('user_nick_name')
    session.pop('is_admin')

    # 2.返回响应
    return jsonify(erron=RET.OK, errmsg='退出成功')



@passport_blu.route('/login', methods=['POST',' GET'])
def login():
    """
    ===>登录功能的实现
    1.接收两个参数, 手机号,密码
    2.校验参数
    3.业务逻辑处理
        3.1 从数据库中去查找指定用户,如果找到校验密码
    4.返回个响应
    :return:
    """
    params = request.json
    mobile = params.get('mobile')
    password = params.get('password')
    if not all([mobile, password]):
        return jsonify(errno=RET.PARAMERR, errmsg='参数错误')

    try:
        user = User.query.filter(User.mobile == mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='查询数据错误')
    if not user:
        return jsonify(errno=RET.USERERR , errmsg='用户没有注册')

    if not user.check_passowrd(password):
        return jsonify(errno=RET.PWDERR, errmsg='密码输入错误')

    # 保持用户登录状态
    session['user_id'] = user.id
    session['user_mobile'] = user.mobile
    session['user_nick_name'] = user.nick_name
    session['is_admin'] = user.is_admin

    # 如果在视图函数中,
    # 记录用户最后一次登录的时间
    """
    注:在视图函数中,如果对模型身上的属性有修改,那么就需要commit提交到数据库保存,
       但是不需要自己写db.session.commit,前提是对SQLAlchemy有相关配置,
       把SQLALCHEMY_COMMIT_ON_TEARDOWN 设置为 True,在请求结束之后, 那么SQLAlchemy会自动执行一次db.session.commit
    """
    user.last_login = datetime.now()

    # try:
    #     db.session.commit()
    # except Exception as e:
    #     current_app.logger.error(e)
    #     return jsonify(errno=RET.PARAMERR, errmsg='数据保存失败')

    return jsonify(errno=RET.OK, errmsg='登录成功')



@passport_blu.route('/register', methods=['post'])
def register():
    """
        注册功能
    1.接三个参数,手机号,短信验证码和 密码
    2.校验参数是否为空
    3.校验手机号是否合法
    4.根据获取的短信验证码id取出数据库中存储的短信验证码内容,去和传入的短信验证码进行对比
    5.把数据存到数据库中 , 5.1.密码加密
    6.保持登录状态
    7.返回一个响应

    :return:
    """
    # 1.接三个参数, 手机号, 短信验证码和密码
    params = request.json
    mobile = params['mobile']
    smscode = params['smscode']
    password = params['password']

    # 2.校验参数是否为空
    if not all([mobile, smscode, password]):
        return jsonify(errno=RET.PARAMERR, errmsg='参数错误')

    # 3.校验手机号是否合法
    if not re.match(r'^1[35789][0-9]{9}$', mobile):
        return jsonify(errno=RET.PARAMERR, errmsg='手机号格式不正确')

    # 4.根据获取的短信验证码id取出数据库中存储的短信验证码内容, 去和传入的短信验证码进行对比
    try:
        sms_code_data = redis_store.get('SMS_'+ mobile)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='短信验证码不存在')
    # 如果没有取到验证码
    if not sms_code_data:
        return jsonify(errno=RET.DBERR, errmsg='验证码过期')

    # 如果验证不一样
    if sms_code_data != smscode:
        return jsonify(errno=RET.PARAMERR, errmsg='短信验证码输入错误')


    # 6.把数据存到数据库中
    user = User()
    user.nick_name = mobile
    user.mobile = mobile
    user.password = password
    user.last_login = datetime.now()

    try:
        db.session.add(user)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DATAERR ,errmsg='存储失败')

    # 6. 保存用户登录状态
    session['user_id'] = user.id
    session['user_nick_name'] = user.nick_name
    session['user_mobile'] = user.mobile
    session['is_admin'] = user.is_admin

    # 6.返回一个响应
    return jsonify(errno=RET.OK, errmsg='注册成功')



@passport_blu.route('/sms_code', methods=['post'])
def send_sms():
    """
    ===发送短信验证码
    1. 接收参数并判断是否有值
    2. 校验手机号是正确
    3. 通过传入的图片编码去redis中查询真实的图片验证码内容
    4. 进行验证码内容的比对
    5. 生成发送短信的内容并发送短信
    6. redis中保存短信验证码内容
    7. 返回发送成功的响应
    :return:
    """
    # 1. 接收参数并判断是否有值
    # 取到请求值中的内容
    # 1,把字符串转成json格式

    parameter = request.json
    mobile = parameter['mobile']  # 手机号码
    image_code = parameter['image_code']  # 验证码的内容
    image_code_id = parameter['image_code_id']  # 验证码的随机编号

    # 获取的内容为空
    if not all([mobile, image_code, image_code_id]):
        return jsonify(errno=RET.PARAMERR, errmsg='参数错误')
    # 判断手机号码
    if not  re.match(r'^1[35789][0-9]{9}$', mobile):
        return jsonify(errno=RET.PARAMERR, errmsg='手机号码错误')

    # 取出数据库中的验证码图片内容与传入的图片验证码内容进行对比
    try:
        real_image_code = redis_store.get('ImageCodeId' + image_code_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='数据查询错误')

    if not real_image_code:
        return jsonify(errno=RET.DBERR, errmsg='验证码已过期')

    if real_image_code.upper() != image_code.upper():
        return jsonify(errno=RET.DATAERR, errmsg='验证码输入错误')

    # 生成短信验证码(必须是6位)
    sms_code = '%06d' % random.randint(0, 999999)
    result = CCP().send_template_sms(mobile, [sms_code, constants.SMS_CODE_REDIS_EXPIRES / 5], '1')
    if result != 0:
        return jsonify(errno=RET.THIRDERR, errmsg='短信验证码发送失败')

    current_app.logger.debug('短信验证码是:%s' % sms_code)

    try:
        redis_store.set('SMS_'+ mobile,sms_code,ex=constants.SMS_CODE_REDIS_EXPIRES)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DATAERR, errmsg='数据存储失败')


    return jsonify(errno=RET.OK, errmgs='短息验证码发送成功')



@passport_blu.route('/image_code')
def passport():

    """ 生成图片验证码 """
    # 1.接收传递过来的参数,这个是验证码的随机编号
    imageCodeId = request.args.get('code_id')

    # 2.校验参数,判断imageCodeId是否为空
    if not imageCodeId:
        abort(403)

    # 3.业务逻辑处理
    # 3.1 校验通过,生成验证码
    name, text, image = captcha.generate_captcha()

    # 3.2把图片存到redis中,并且设置过期时间
    redis_store.set('ImageCodeId' + imageCodeId, text,ex=IMAGE_CODE_REDIS_EXPIRES)

    current_app.logger.debug('图片验证码是:%s' % text)

    # 4,返回结果
    # 4.1生成响应
    response = make_response(image)
    # 4.2指定响应的类型
    response.headers['Content-Type'] = 'image/jgp'
    # 返回这个响应
    return response
